//////////////////////////////////////////////////////////////////////////
//
// Vector Graph Core2D
//
// Module:
//        Box2D.cs
//
// Description:
//        Implementation of calculating bounding box
//
// Author:
//        Created on 2008.04.14 by Destrayer
//
//////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace VectorGraph.Core2D
{
    public class Box2D
    {
        public static void Expand(ref Rectangle2d box, Point2d pt)
        {
            if (pt.X < box.Left)
            {
                box.Left = pt.X;
            }
            else if (pt.X > box.Right)
            {
                box.Right = pt.X;
            }
            if (pt.Y < box.Bottom)
            {
                box.Bottom = pt.Y;
            }
            else if (pt.Y > box.Top)
            {
                box.Top = pt.Y;
            }
        }

        public static Rectangle2d Box(Point2d pt)
        {
            return new Rectangle2d(pt);
        }

        public static Rectangle2d Box(Circle2d circle)
        {
            Rectangle2d r = new Rectangle2d();
            r.Left = circle.CenterPt.X - circle.Radius;
            r.Right = circle.CenterPt.X + circle.Radius;
            r.Bottom = circle.CenterPt.Y - circle.Radius;
            r.Top = circle.CenterPt.Y + circle.Radius;
            return r;
        }

        public static Rectangle2d Box(Segment2d segment)
        {
            Rectangle2d r = new Rectangle2d(segment.StartPt);
            Box2D.Expand(ref r, segment.EndPt);
            return r;
        }

        public static Rectangle2d Box(Arc2d arc)
        {
            Rectangle2d r = new Rectangle2d(arc.CenterPt + arc.StartVector);
            Box2D.Expand(ref r, arc.CenterPt + arc.EndVector);
            double startAngle = arc.StartAngle;
            double endAngle = startAngle + arc.SweepAngle;
            double radius = arc.StartVector.Length;
            if (endAngle < Math.PI)
            {
                if (startAngle < -Math.PI / 2 && -Math.PI / 2 < endAngle)
                {
                    Box2D.Expand(ref r, arc.CenterPt + new Point2d(0, -radius));
                }
                if (startAngle < 0 && 0 < endAngle)
                {
                    Box2D.Expand(ref r, arc.CenterPt + new Point2d(radius, 0));
                }
                if (startAngle < Math.PI / 2 && Math.PI / 2 < endAngle)
                {
                    Box2D.Expand(ref r, arc.CenterPt + new Point2d(0, radius));
                }
            }
            else
            {
                endAngle -= 2 * Math.PI;
                Box2D.Expand(ref r, arc.CenterPt + new Point2d(-radius, 0));
                if (startAngle < -Math.PI / 2 || -Math.PI / 2 < endAngle)
                {
                    Box2D.Expand(ref r, arc.CenterPt + new Point2d(0, -radius));
                }
                if (startAngle < 0 || 0 < endAngle)
                {
                    Box2D.Expand(ref r, arc.CenterPt + new Point2d(radius, 0));
                }
                if (startAngle < Math.PI / 2 || Math.PI / 2 < endAngle)
                {
                    Box2D.Expand(ref r, arc.CenterPt + new Point2d(0, radius));
                }
            }
            return r;
        }

        public static Rectangle2d Box(Path2d path)
        {
            Rectangle2d r = new Rectangle2d(path.Vertex(0));
            foreach (Point2d pt in path.Vertices)
            {
                Box2D.Expand(ref r, pt);
            }
            return r;
        }

        public static bool BoxIntBox(Rectangle2d box1, Rectangle2d box2, out Rectangle2d outBox)
        {
            outBox = new Rectangle2d(
                Math.Max(box1.Left, box2.Left),     // left
                Math.Max(box1.Bottom, box2.Bottom), // bottom
                Math.Min(box1.Right, box2.Right),   // right
                Math.Min(box1.Top, box2.Top));      // top
            return outBox.Left < outBox.Right && outBox.Bottom < outBox.Top;
        }

        public static bool BoxIntBox(Rectangle2d box1, Rectangle2d box2)
        {
            return Math.Max(box1.Left, box2.Left) < Math.Min(box1.Right, box2.Right) &&
                Math.Max(box1.Bottom, box2.Bottom) < Math.Min(box1.Top, box2.Top);
        }
    }
}